Shiny

Shiny is an R package that makes it easy to build interactive web apps straight from R. You can host standalone apps on a webpage or embed them in R Markdown documents or build dashboards. You can also extend your Shiny apps with CSS themes, htmlwidgets, and JavaScript actions.

Shiny is most often used with the packages “shinydashboard” or “flexdashboard” to build interactive dashboards. We will walk through how to use both shinydashboard and flexdashboard to give you options when using shiny.

Shiny dashboard structure (UI - user interface)

3 Main parts:

  • Header - dashboardHeader()
  • Sidebar - dashboardSidebar()
  • Body - dashboardBody()

How to build a Sidebar Dashboard

library(shinydashboard)

sidebar <- dashboardSidebar(
  sidebarMenu(
    menuItem("Data",
      tabName = "data") #Used for linking in the body
  )
)

If you want more interactivity on your dashboard, shiny has some functions that enables you to do that. You can use a number of different input options using shiny. This allows the user of the website to input information - whether it’s text, a date, or to select options from data that you provide.

Different input functions: * selectInput() # Allows user to select a singular item from a list * textInput() # Allows user to input text * dateInput() # Allows user to input a date * checkboxInput()

How to build user input with shinydashboard

library("shiny")
library("tidyverse")

selectInput(
  inputId = "object", # This is the name you described the object elsewhere in the application
  label = "Favorite Character", # The label you want to show to the user
  choices = c(starwars$name) # List the choices the user has to pick from
 )

Render Functions

Functions that you use in your application’s server side code, assigning them to outputs that appear in your user interface.

  • renderPrint()
  • renderText()
  • renderPlot()
  • renderUI() # HTML or a shiny tag object

Example Using Star Wars df

library(shiny)
There were 42 warnings (use warnings() to see them)
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages --------------------------------------- tidyverse 1.3.0 --
v ggplot2 3.3.1     v purrr   0.3.4
v tibble  3.0.1     v dplyr   1.0.0
v tidyr   1.1.0     v stringr 1.4.0
v readr   1.3.1     v forcats 0.5.0
-- Conflicts ------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(shinydashboard)

Attaching package: 㤼㸱shinydashboard㤼㸲

The following object is masked from 㤼㸱package:graphics㤼㸲:

    box
header <- dashboardHeader(
  title = "Example Dashboard Header",
  titleWidth = 300
)

sidebar <- dashboardSidebar(
  selectInput(
    inputId = "name",
    label = "Favorite Character",
    choices = c(starwars$name)
  )
)

body <- dashboardBody(
  textOutput("name")
)

After you code the sidebar and body, you can then create the User Interface, or “ui”. The User Interface is built from a header, sidebar, and body. When you modify any of these options, the easiest way is to save it as an object called “header”, “sidebar”, or “body”. The user interface is most often coded into the dashboardPage() function.

ui <- dashboardPage(header = header,
                    sidebar = sidebar,
                    body = body
                    )

server <- function(input, output) {
  output$name <- renderText({
      input$name
    })
}

shinyApp(ui, server)

Shinydashboard Layout

There are two main types of layouts that shiny uses. The first is a “row” based layout, while the other is a “column” based layout. You can use either one, or even a mix of the two. The way to create the layouts is by using the “fluidRow()” function.

These functions are used inside of the dashboardBody() section. Each time “fluidRow()” is called, a new row is created.

Row layout

body <- dashboardBody(
  fluidRow(
# Row 1
  box(
  width = 12, # 12 width spans the entire width of the screen
  title = "Regular Box, Row 1",
  "Text inside of box"
  )),
  fluidRow(
# Row 2
  box(
  width = 12,
  title = "Regular Box, Row 2",
  "Text inside of box 2"
  )
)
)
ui <- dashboardPage(header = dashboardHeader(),
                    sidebar = dashboardSidebar(),
                    body = body
                    )

ui

Column Layout

The next layout option is to build columns. The difference in using columns instead of rows is to use the “column()” function inside of “fluidRow()”.

You can set the width of the column, but when you insert a box or chart, the width needs to be “NULL”.

body <- dashboardBody(
    fluidRow(
    #   Column 1
      column(width = 6,
      infoBox(
        width = NULL, # The width must be "NULL" when using a column layout
        title = "Regular Box, Column 1",
        "Text inside of box"
         )      
   ),
  column(width = 6,
    #   Column 2
      infoBox(
        width = NULL, # The width must be "NULL" when using a column layout
        title = "Regular Box, Column 2",
        "Text inside of box"
         )      
   )
)
)
ui <- dashboardPage(header = dashboardHeader(),
                    sidebar = dashboardSidebar(),
                    body = body
                    )

shinyApp(ui, server)

Mix of Column and Row Layout

Note: To create a new row, call another fluidRow() function.

body <- dashboardBody(
    fluidRow(
    #   Row 1
      box(
        width = 12, # The width must be "NULL" when using a column layout
        title = "Regular Box, Row 1",
        "Text inside of box"
         ),
    ),
  fluidRow(
    column(width = 6,
    #   Column 2
      infoBox(
        width = NULL, # The width must be "NULL" when using a column layout
        title = "Regular Box, Row 2, Column 1",
        subtitle = "Text inside of box"
         )
    ),
    column(width = 6,
      infoBox(
        width = NULL,
        title = "Regular Box, Row 2, Column 2",
        subtitle = "Text inside of box"
      )
    )
  )
)

ui <- dashboardPage(header = dashboardHeader(),
                    sidebar = dashboardSidebar(),
                    body = body
                    )

shinyApp(ui, server)
LS0tDQp0aXRsZTogIlNoaW55IFdhbGt0aHJvdWdoIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KIyBTaGlueQ0KDQpTaGlueSBpcyBhbiBSIHBhY2thZ2UgdGhhdCBtYWtlcyBpdCBlYXN5IHRvIGJ1aWxkIGludGVyYWN0aXZlIHdlYiBhcHBzIHN0cmFpZ2h0IGZyb20gUi4gWW91IGNhbiBob3N0IHN0YW5kYWxvbmUgYXBwcyBvbiBhIHdlYnBhZ2Ugb3IgZW1iZWQgdGhlbSBpbiBSIE1hcmtkb3duIGRvY3VtZW50cyBvciBidWlsZCBkYXNoYm9hcmRzLiBZb3UgY2FuIGFsc28gZXh0ZW5kIHlvdXIgU2hpbnkgYXBwcyB3aXRoIENTUyB0aGVtZXMsIGh0bWx3aWRnZXRzLCBhbmQgSmF2YVNjcmlwdCBhY3Rpb25zLg0KDQpTaGlueSBpcyBtb3N0IG9mdGVuIHVzZWQgd2l0aCB0aGUgcGFja2FnZXMgInNoaW55ZGFzaGJvYXJkIiBvciAiZmxleGRhc2hib2FyZCIgdG8gYnVpbGQgaW50ZXJhY3RpdmUgZGFzaGJvYXJkcy4gV2Ugd2lsbCB3YWxrIHRocm91Z2ggaG93IHRvIHVzZSBib3RoIHNoaW55ZGFzaGJvYXJkIGFuZCBmbGV4ZGFzaGJvYXJkIHRvIGdpdmUgeW91IG9wdGlvbnMgd2hlbiB1c2luZyBzaGlueS4NCg0KDQojIyBTaGlueSBkYXNoYm9hcmQgc3RydWN0dXJlIChVSSAtIHVzZXIgaW50ZXJmYWNlKQ0KDQozIE1haW4gcGFydHM6DQoNCiogSGVhZGVyIC0gZGFzaGJvYXJkSGVhZGVyKCkNCiogU2lkZWJhciAtIGRhc2hib2FyZFNpZGViYXIoKQ0KKiBCb2R5IC0gZGFzaGJvYXJkQm9keSgpDQoNCg0KIyMjIEhvdyB0byBidWlsZCBhIFNpZGViYXIgRGFzaGJvYXJkDQoNCmBgYHtyfQ0KbGlicmFyeShzaGlueWRhc2hib2FyZCkNCg0Kc2lkZWJhciA8LSBkYXNoYm9hcmRTaWRlYmFyKA0KICBzaWRlYmFyTWVudSgNCiAgICBtZW51SXRlbSgiRGF0YSIsDQogICAgICB0YWJOYW1lID0gImRhdGEiKSAjVXNlZCBmb3IgbGlua2luZyBpbiB0aGUgYm9keQ0KICApDQopDQpgYGANCg0KSWYgeW91IHdhbnQgbW9yZSBpbnRlcmFjdGl2aXR5IG9uIHlvdXIgZGFzaGJvYXJkLCBzaGlueSBoYXMgc29tZSBmdW5jdGlvbnMgdGhhdCBlbmFibGVzIHlvdSB0byBkbyB0aGF0LiBZb3UgY2FuIHVzZSBhIG51bWJlciBvZiBkaWZmZXJlbnQgaW5wdXQgb3B0aW9ucyB1c2luZyBzaGlueS4gVGhpcyBhbGxvd3MgdGhlIHVzZXIgb2YgdGhlIHdlYnNpdGUgdG8gaW5wdXQgaW5mb3JtYXRpb24gLSB3aGV0aGVyIGl0J3MgdGV4dCwgYSBkYXRlLCBvciB0byBzZWxlY3Qgb3B0aW9ucyBmcm9tIGRhdGEgdGhhdCB5b3UgcHJvdmlkZS4NCg0KRGlmZmVyZW50IGlucHV0IGZ1bmN0aW9uczoNCiogc2VsZWN0SW5wdXQoKSAjIEFsbG93cyB1c2VyIHRvIHNlbGVjdCBhIHNpbmd1bGFyIGl0ZW0gZnJvbSBhIGxpc3QNCiogdGV4dElucHV0KCkgIyBBbGxvd3MgdXNlciB0byBpbnB1dCB0ZXh0DQoqIGRhdGVJbnB1dCgpICMgQWxsb3dzIHVzZXIgdG8gaW5wdXQgYSBkYXRlDQoqIGNoZWNrYm94SW5wdXQoKQ0KDQoNCiMjIyBIb3cgdG8gYnVpbGQgdXNlciBpbnB1dCB3aXRoIHNoaW55ZGFzaGJvYXJkDQoNCmBgYHtyfQ0KbGlicmFyeSgic2hpbnkiKQ0KbGlicmFyeSgidGlkeXZlcnNlIikNCg0Kc2VsZWN0SW5wdXQoDQogIGlucHV0SWQgPSAib2JqZWN0IiwgIyBUaGlzIGlzIHRoZSBuYW1lIHlvdSBkZXNjcmliZWQgdGhlIG9iamVjdCBlbHNld2hlcmUgaW4gdGhlIGFwcGxpY2F0aW9uDQogIGxhYmVsID0gIkZhdm9yaXRlIENoYXJhY3RlciIsICMgVGhlIGxhYmVsIHlvdSB3YW50IHRvIHNob3cgdG8gdGhlIHVzZXINCiAgY2hvaWNlcyA9IGMoc3RhcndhcnMkbmFtZSkgIyBMaXN0IHRoZSBjaG9pY2VzIHRoZSB1c2VyIGhhcyB0byBwaWNrIGZyb20NCiApDQpgYGANCg0KDQojIyMgUmVuZGVyIEZ1bmN0aW9ucyANCkZ1bmN0aW9ucyB0aGF0IHlvdSB1c2UgaW4geW91ciBhcHBsaWNhdGlvbidzIHNlcnZlciBzaWRlIGNvZGUsIGFzc2lnbmluZyB0aGVtIHRvIG91dHB1dHMgdGhhdCBhcHBlYXIgaW4geW91ciB1c2VyIGludGVyZmFjZS4NCg0KKiByZW5kZXJQcmludCgpDQoqIHJlbmRlclRleHQoKQ0KKiByZW5kZXJQbG90KCkNCiogcmVuZGVyVUkoKSAjIEhUTUwgb3IgYSBzaGlueSB0YWcgb2JqZWN0DQoNCiMjIEV4YW1wbGUgVXNpbmcgU3RhciBXYXJzIGRmDQpgYGB7cn0NCmxpYnJhcnkoc2hpbnkpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoc2hpbnlkYXNoYm9hcmQpDQoNCmhlYWRlciA8LSBkYXNoYm9hcmRIZWFkZXIoDQogIHRpdGxlID0gIkV4YW1wbGUgRGFzaGJvYXJkIEhlYWRlciIsDQogIHRpdGxlV2lkdGggPSAzMDANCikNCg0Kc2lkZWJhciA8LSBkYXNoYm9hcmRTaWRlYmFyKA0KICBzZWxlY3RJbnB1dCgNCiAgICBpbnB1dElkID0gIm5hbWUiLA0KICAgIGxhYmVsID0gIkZhdm9yaXRlIENoYXJhY3RlciIsDQogICAgY2hvaWNlcyA9IGMoc3RhcndhcnMkbmFtZSkNCiAgKQ0KKQ0KDQpib2R5IDwtIGRhc2hib2FyZEJvZHkoDQogIHRleHRPdXRwdXQoIm5hbWUiKQ0KKQ0KYGBgDQoNCg0KQWZ0ZXIgeW91IGNvZGUgdGhlIHNpZGViYXIgYW5kIGJvZHksIHlvdSBjYW4gdGhlbiBjcmVhdGUgdGhlIFVzZXIgSW50ZXJmYWNlLCBvciAidWkiLiBUaGUgVXNlciBJbnRlcmZhY2UgaXMgYnVpbHQgZnJvbSBhIGhlYWRlciwgc2lkZWJhciwgYW5kIGJvZHkuIFdoZW4geW91IG1vZGlmeSBhbnkgb2YgdGhlc2Ugb3B0aW9ucywgdGhlIGVhc2llc3Qgd2F5IGlzIHRvIHNhdmUgaXQgYXMgYW4gb2JqZWN0IGNhbGxlZCAiaGVhZGVyIiwgInNpZGViYXIiLCBvciAiYm9keSIuIFRoZSB1c2VyIGludGVyZmFjZSBpcyBtb3N0IG9mdGVuIGNvZGVkIGludG8gdGhlIGRhc2hib2FyZFBhZ2UoKSBmdW5jdGlvbi4NCg0KDQpgYGB7cn0NCnVpIDwtIGRhc2hib2FyZFBhZ2UoaGVhZGVyID0gaGVhZGVyLA0KICAgICAgICAgICAgICAgICAgICBzaWRlYmFyID0gc2lkZWJhciwNCiAgICAgICAgICAgICAgICAgICAgYm9keSA9IGJvZHkNCiAgICAgICAgICAgICAgICAgICAgKQ0KDQpzZXJ2ZXIgPC0gZnVuY3Rpb24oaW5wdXQsIG91dHB1dCkgew0KICBvdXRwdXQkbmFtZSA8LSByZW5kZXJUZXh0KHsNCiAgICAgIGlucHV0JG5hbWUNCiAgICB9KQ0KfQ0KDQpzaGlueUFwcCh1aSwgc2VydmVyKQ0KDQpgYGANCg0KDQoNCiMjIFNoaW55ZGFzaGJvYXJkIExheW91dA0KDQpUaGVyZSBhcmUgdHdvIG1haW4gdHlwZXMgb2YgbGF5b3V0cyB0aGF0IHNoaW55IHVzZXMuIFRoZSBmaXJzdCBpcyBhICJyb3ciIGJhc2VkIGxheW91dCwgd2hpbGUgdGhlIG90aGVyIGlzIGEgImNvbHVtbiIgYmFzZWQgbGF5b3V0LiBZb3UgY2FuIHVzZSBlaXRoZXIgb25lLCBvciBldmVuIGEgbWl4IG9mIHRoZSB0d28uDQpUaGUgd2F5IHRvIGNyZWF0ZSB0aGUgbGF5b3V0cyBpcyBieSB1c2luZyB0aGUgImZsdWlkUm93KCkiIGZ1bmN0aW9uLiANCg0KVGhlc2UgZnVuY3Rpb25zIGFyZSB1c2VkIGluc2lkZSBvZiB0aGUgZGFzaGJvYXJkQm9keSgpIHNlY3Rpb24uIEVhY2ggdGltZSAiZmx1aWRSb3coKSIgaXMgY2FsbGVkLCBhIG5ldyByb3cgaXMgY3JlYXRlZC4gDQoNCiMjIyBSb3cgbGF5b3V0DQpgYGB7cn0NCmJvZHkgPC0gZGFzaGJvYXJkQm9keSgNCiAgZmx1aWRSb3coDQojIFJvdyAxDQogIGJveCgNCiAgd2lkdGggPSAxMiwgIyAxMiB3aWR0aCBzcGFucyB0aGUgZW50aXJlIHdpZHRoIG9mIHRoZSBzY3JlZW4NCiAgdGl0bGUgPSAiUmVndWxhciBCb3gsIFJvdyAxIiwNCiAgIlRleHQgaW5zaWRlIG9mIGJveCINCiAgKSksDQogIGZsdWlkUm93KA0KIyBSb3cgMg0KICBib3goDQogIHdpZHRoID0gMTIsDQogIHRpdGxlID0gIlJlZ3VsYXIgQm94LCBSb3cgMiIsDQogICJUZXh0IGluc2lkZSBvZiBib3ggMiINCiAgKQ0KKQ0KKQ0KdWkgPC0gZGFzaGJvYXJkUGFnZShoZWFkZXIgPSBkYXNoYm9hcmRIZWFkZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgc2lkZWJhciA9IGRhc2hib2FyZFNpZGViYXIoKSwNCiAgICAgICAgICAgICAgICAgICAgYm9keSA9IGJvZHkNCiAgICAgICAgICAgICAgICAgICAgKQ0KDQp1aQ0KYGBgDQoNCiMjIyBDb2x1bW4gTGF5b3V0DQpUaGUgbmV4dCBsYXlvdXQgb3B0aW9uIGlzIHRvIGJ1aWxkIGNvbHVtbnMuIFRoZSBkaWZmZXJlbmNlIGluIHVzaW5nIGNvbHVtbnMgaW5zdGVhZCBvZiByb3dzIGlzIHRvIHVzZSB0aGUgImNvbHVtbigpIiBmdW5jdGlvbiBpbnNpZGUgb2YgImZsdWlkUm93KCkiLiANCg0KWW91IGNhbiBzZXQgdGhlIHdpZHRoIG9mIHRoZSBjb2x1bW4sIGJ1dCB3aGVuIHlvdSBpbnNlcnQgYSBib3ggb3IgY2hhcnQsIHRoZSB3aWR0aCBuZWVkcyB0byBiZSAiTlVMTCIuIA0KDQoNCmBgYHtyfQ0KYm9keSA8LSBkYXNoYm9hcmRCb2R5KA0KICAgIGZsdWlkUm93KA0KICAgICMgICBDb2x1bW4gMQ0KICAgICAgY29sdW1uKHdpZHRoID0gNiwNCiAgICAgIGluZm9Cb3goDQogICAgICAgIHdpZHRoID0gTlVMTCwgIyBUaGUgd2lkdGggbXVzdCBiZSAiTlVMTCIgd2hlbiB1c2luZyBhIGNvbHVtbiBsYXlvdXQNCiAgICAgICAgdGl0bGUgPSAiUmVndWxhciBCb3gsIENvbHVtbiAxIiwNCiAgICAgICAgIlRleHQgaW5zaWRlIG9mIGJveCINCiAgICAgICAgICkgICAgICANCiAgICksDQogIGNvbHVtbih3aWR0aCA9IDYsDQogICAgIyAgIENvbHVtbiAyDQogICAgICBpbmZvQm94KA0KICAgICAgICB3aWR0aCA9IE5VTEwsICMgVGhlIHdpZHRoIG11c3QgYmUgIk5VTEwiIHdoZW4gdXNpbmcgYSBjb2x1bW4gbGF5b3V0DQogICAgICAgIHRpdGxlID0gIlJlZ3VsYXIgQm94LCBDb2x1bW4gMiIsDQogICAgICAgICJUZXh0IGluc2lkZSBvZiBib3giDQogICAgICAgICApICAgICAgDQogICApDQopDQopDQp1aSA8LSBkYXNoYm9hcmRQYWdlKGhlYWRlciA9IGRhc2hib2FyZEhlYWRlcigpLA0KICAgICAgICAgICAgICAgICAgICBzaWRlYmFyID0gZGFzaGJvYXJkU2lkZWJhcigpLA0KICAgICAgICAgICAgICAgICAgICBib2R5ID0gYm9keQ0KICAgICAgICAgICAgICAgICAgICApDQoNCnNoaW55QXBwKHVpLCBzZXJ2ZXIpDQpgYGANCg0KDQojIyMgTWl4IG9mIENvbHVtbiBhbmQgUm93IExheW91dA0KTm90ZToNClRvIGNyZWF0ZSBhIG5ldyByb3csIGNhbGwgYW5vdGhlciBmbHVpZFJvdygpIGZ1bmN0aW9uLiANCmBgYHtyfQ0KYm9keSA8LSBkYXNoYm9hcmRCb2R5KA0KICAgIGZsdWlkUm93KA0KICAgICMgICBSb3cgMQ0KICAgICAgYm94KA0KICAgICAgICB3aWR0aCA9IDEyLCAjIFRoZSB3aWR0aCBtdXN0IGJlICJOVUxMIiB3aGVuIHVzaW5nIGEgY29sdW1uIGxheW91dA0KICAgICAgICB0aXRsZSA9ICJSZWd1bGFyIEJveCwgUm93IDEiLA0KICAgICAgICAiVGV4dCBpbnNpZGUgb2YgYm94Ig0KICAgICAgICAgKSwNCiAgICApLA0KICBmbHVpZFJvdygNCiAgICBjb2x1bW4od2lkdGggPSA2LA0KICAgICMgICBDb2x1bW4gMg0KICAgICAgaW5mb0JveCgNCiAgICAgICAgd2lkdGggPSBOVUxMLCAjIFRoZSB3aWR0aCBtdXN0IGJlICJOVUxMIiB3aGVuIHVzaW5nIGEgY29sdW1uIGxheW91dA0KICAgICAgICB0aXRsZSA9ICJSZWd1bGFyIEJveCwgUm93IDIsIENvbHVtbiAxIiwNCiAgICAgICAgc3VidGl0bGUgPSAiVGV4dCBpbnNpZGUgb2YgYm94Ig0KICAgICAgICAgKQ0KICAgICksDQogICAgY29sdW1uKHdpZHRoID0gNiwNCiAgICAgIGluZm9Cb3goDQogICAgICAgIHdpZHRoID0gTlVMTCwNCiAgICAgICAgdGl0bGUgPSAiUmVndWxhciBCb3gsIFJvdyAyLCBDb2x1bW4gMiIsDQogICAgICAgIHN1YnRpdGxlID0gIlRleHQgaW5zaWRlIG9mIGJveCINCiAgICAgICkNCiAgICApDQogICkNCikNCg0KdWkgPC0gZGFzaGJvYXJkUGFnZShoZWFkZXIgPSBkYXNoYm9hcmRIZWFkZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgc2lkZWJhciA9IGRhc2hib2FyZFNpZGViYXIoKSwNCiAgICAgICAgICAgICAgICAgICAgYm9keSA9IGJvZHkNCiAgICAgICAgICAgICAgICAgICAgKQ0KDQpzaGlueUFwcCh1aSwgc2VydmVyKQ0KYGBgDQoNCg0KDQoNCg0K